package org.ejc.api.transaction;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.ejb.SessionBean;

import org.apache.log4j.Category;
import org.ejc.api.registration.RegistrationAPIBean;
import org.ejc.api.registration.RegistrationAPIUtil;
import org.ejc.datatype.transaction.EJCTxSearchResult;
import org.ejc.datatype.transaction.ExecTransactionDetail;
import org.ejc.exception.EJCPersistenceException;
import org.ejc.persist.model.Convention;
import org.ejc.persist.model.ConventionActivityHistory;
import org.ejc.persist.model.ConventionExecutive;
import org.ejc.persist.model.Registrant;
import org.ejc.persist.model.Transaction;
import org.ejc.util.EJCUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;

/**
 * @author Brian Boyle
 * 
 * @ejb.bean type="Stateless" name="TransactionAPI" description="TransactionAPI
 *           session bean" local-jndi-name="org.ejc/TransactionAPILocalHome"
 *           jndi-name="org.ejc/TransactionAPIHome" view-type="both"
 * 
 * @ejb.ejb-ref ejb-name="TransactionAPI" ref-name="ejb/TransactionAPI"
 *              view-type="both"
 * 
 * @ejb.transaction type="RequiresNew"
 * @ejb.util generate = "physical"
 */
public abstract class TransactionAPIBean implements SessionBean {

	Category log = Category.getInstance(TransactionAPIBean.class);
	private final static Integer BATCH_EXEC=-1;

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Transaction getTransactionByRegistrantId(Registrant registrant) {
		Session hsession = null;
		Transaction transaction = null;
		try {
			hsession = EJCUtils.getHibernateSession();
			log.debug("Searching for Transaction with ID ["
					+ registrant.getRegistrantId() + "]");
			transaction = (Transaction) hsession.createCriteria(
					Transaction.class).add(
					Expression.eq("registrant", registrant)).uniqueResult();
			log.debug("Found Transaction for Id ["
					+ registrant.getRegistrantId() + "]");
		} catch (EJCPersistenceException e) {
			log
					.fatal("Error getting Hibernate Session instance when selecting a Registrant by Id");
			e.printStackTrace();
		}
		return transaction;
	}

	private ExecTransactionDetail getTransactionListing(Date fromDate,
			Date toDate, ConventionExecutive convExec) {

		Session hSession = null;
		ExecTransactionDetail execDetail = new ExecTransactionDetail();

		try {
			hSession = EJCUtils.getHibernateSession();
			Criteria criteria = hSession.createCriteria(Transaction.class);

			criteria.add(Expression.ge("transactionDate", fromDate));
			criteria.add(Expression.le("transactionDate", toDate));
			criteria.add(Expression.eq("conventionExecutive", convExec));

			List results = criteria.list();
			Double txValue = 0.0;
			for (Iterator iter = results.iterator(); iter.hasNext();) {
				Transaction element = (Transaction) iter.next();
				txValue += element.getTransactionAmount();
			}
			execDetail.setNumTransaction(results.size());
			execDetail.setTransactionsValue(txValue);
			execDetail.setExecutiveId(convExec.getExecutiveId());

		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}

		return execDetail;
	}

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public List getCurrentSessionTransactionsForExecutive(Integer executiveId, int resultIndex, int resultSize) {
		List returnList = new ArrayList();
		Session hSession = null;

		try {
			hSession = EJCUtils.getHibernateSession();
			ConventionExecutive convExec = (ConventionExecutive) hSession.load(
					ConventionExecutive.class, executiveId);
			Date fromDate = RegistrationAPIUtil.getLocalHome().create()
					.getLastActiveDate();
			Date toDate = RegistrationAPIUtil.getLocalHome().create()
					.getLastInActiveDate();

			Criteria criteria = hSession.createCriteria(Transaction.class);

			criteria.add(Expression.ge("transactionDate", fromDate));
			criteria.add(Expression.le("transactionDate", toDate));
			criteria.add(Expression.eq("conventionExecutive", convExec));
			List results = null;
			if(resultSize != 0){
				results = criteria.setFirstResult(resultIndex).setMaxResults(resultSize).list();
			}else{
				results = criteria.list();
			}
			

			for (Iterator iter = results.iterator(); iter.hasNext();) {
				Transaction element = (Transaction) iter.next();
				Transaction newTrans = new Transaction();
				newTrans.setTransactionDate(element.getTransactionDate());
				newTrans.setTransactionId(element.getTransactionId());
				newTrans.setTransactionAmount(element.getTransactionAmount());

				
				Registrant r = new Registrant();
				r.setFirstName(element.getRegistrant().getFirstName());
				r.setLastName(element.getRegistrant().getLastName());
				newTrans.setRegistrant(r);
				returnList.add(newTrans);
			}

		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}

		return returnList;

	}

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public EJCTxSearchResult getTxDetailsPerPeriod(Date fromDate, Date toDate,
			Integer conventionId) {
		Session hSession = null;
		Integer numTxs = 0;
		
		log.fatal("From date is "+fromDate);
		log.fatal("To Date is "+toDate);

		Double totalValue = 0.0;
		EJCTxSearchResult result = new EJCTxSearchResult();

		try {
			hSession = EJCUtils.getHibernateSession();
			Convention convention = (Convention) hSession.load(
					Convention.class, new Integer(1));

			Criteria criteria = hSession.createCriteria(Transaction.class);

			criteria.add(Expression.ge("transactionDate", fromDate));
			criteria.add(Expression.le("transactionDate", toDate));
			criteria.add(Expression.eq("convention", convention));

			List results = criteria.list();
			numTxs = results.size();
			log.fatal("Num of Tx's is "+numTxs);

			for (Iterator iter = results.iterator(); iter.hasNext();) {
				Transaction element = (Transaction) iter.next();
				if(element.getTransactionAmount()==null){
					log.fatal("Tx with a null value !! "+element.getTransactionId());
					continue;
				}
				totalValue += element.getTransactionAmount();
			}

			result.setFromDate(fromDate);
			result.setToDate(toDate);
			result.setNumTxs(numTxs);
			result.setTotalValue(totalValue);

		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}

		return result;

	}

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public List getExecTransactions(Date fromDate, Date toDate) {
		List returnList = new ArrayList();

		Session hSession = null;
		ExecTransactionDetail finalDetail = new ExecTransactionDetail();
		Double moneyCounter = 0.0;
		Integer totalTxs = 0;

		try {
			hSession = EJCUtils.getHibernateSession();
			Criteria crit = hSession.createCriteria(ConventionExecutive.class);
			List execs = crit.list();
			for (Iterator iter = execs.iterator(); iter.hasNext();) {
				ConventionExecutive element = (ConventionExecutive) iter.next();
				ExecTransactionDetail detail = getTransactionListing(fromDate,
						toDate, element);

				moneyCounter += detail.getTransactionsValue();
				totalTxs += detail.getNumTransaction();

				detail.setExecName(element.getFirstName() + " "
						+ element.getLastName());
				returnList.add(detail);

			}
			finalDetail.setExecName("Cumulative Totals");
			finalDetail.setNumTransaction(totalTxs);
			finalDetail.setTransactionsValue(moneyCounter);
			returnList.add(finalDetail);
		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}
		return returnList;
	}

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public List getTransactionListingForActivityPeriod(Integer periodId, int resultIndex, int resultSize) {
		List returnList = new ArrayList();
		Session hSession = null;
		try {
			hSession = EJCUtils.getHibernateSession();
			ConventionActivityHistory history = (ConventionActivityHistory) hSession
					.load(ConventionActivityHistory.class, periodId);
			Date fromDate = history.getStartTime();
			Date toDate = history.getEndTime();

			Criteria criteria = hSession.createCriteria(Transaction.class);
			criteria.add(Expression.ge("transactionDate", fromDate));
			criteria.add(Expression.le("transactionDate", toDate));

			criteria.addOrder(Order.desc("conventionExecutive.executiveId"));

			// criteria.add(Projections.groupProperty("22"));

			List transactions = criteria.setFirstResult(resultIndex).setMaxResults(resultSize).list();
			for (Iterator iter = transactions.iterator(); iter.hasNext();) {
				Transaction element = (Transaction) iter.next();
				Transaction tmpTransction = new Transaction();
				tmpTransction.setTransactionId(element.getTransactionId());
				tmpTransction.setTransactionAmount(element
						.getTransactionAmount());
				tmpTransction.setTransactionDate(element.getTransactionDate());
				tmpTransction.setTransactionId(element.getTransactionId());

				ConventionExecutive convExec = new ConventionExecutive();
				convExec.setFirstName(element.getConventionExecutive()
						.getFirstName()
						+ " " + element.getConventionExecutive().getLastName());
				convExec.setExecutiveId(element.getConventionExecutive().getExecutiveId());
				tmpTransction.setConventionExecutive(convExec);

				Registrant r = new Registrant();
				r.setFirstName(element.getRegistrant().getFirstName());
				r.setLastName(element.getRegistrant().getLastName());
				tmpTransction.setRegistrant(r);
				returnList.add(tmpTransction);
			}

		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}

		return returnList;
	}

	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public List getAllCurrentSessionTransactions(Integer conventionId, int resultIndex, int resultSize) {
		List returnList = new ArrayList();
		Session hSession = null;
		try {
			hSession = EJCUtils.getHibernateSession();
			Convention convention=(Convention)hSession.load(Convention.class,conventionId);
			
			Criteria criteria = hSession.createCriteria(Transaction.class);
			criteria.add(Expression.ge("transactionDate", convention.getConventionStatusLastActive()));
			
			List transactions = criteria.setFirstResult(resultIndex).setMaxResults(resultSize).list();
			for (Iterator iter = transactions.iterator(); iter.hasNext();) {
				Transaction element = (Transaction) iter.next();
				Transaction tmpTransction = new Transaction();
				tmpTransction.setTransactionId(element.getTransactionId());
				tmpTransction.setTransactionAmount(element
						.getTransactionAmount());
				tmpTransction.setTransactionDate(element.getTransactionDate());
				tmpTransction.setTransactionId(element.getTransactionId());

				ConventionExecutive convExec = new ConventionExecutive();
				convExec.setFirstName(element.getConventionExecutive()
						.getFirstName()
						+ " " + element.getConventionExecutive().getLastName());
				convExec.setExecutiveId(element.getConventionExecutive().getExecutiveId());
				tmpTransction.setConventionExecutive(convExec);

				Registrant r = new Registrant();
				r.setFirstName(element.getRegistrant().getFirstName());
				r.setLastName(element.getRegistrant().getLastName());
				tmpTransction.setRegistrant(r);
				returnList.add(tmpTransction);
			}
			
			
		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}

		return returnList;
	}
	
	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Double getTotalPreRegisteredTxValue(){
		Session hSession = null;
		Double returnVal=0.0;
		try {
			hSession = EJCUtils.getHibernateSession();
			ConventionExecutive exec=(ConventionExecutive)hSession.load(ConventionExecutive.class,new Integer(BATCH_EXEC));
			Query q=hSession.createQuery("select sum(transaction.transactionAmount) from Transaction transaction where transaction.conventionExecutive=?");
			q.setParameter(0,exec);
			returnVal=(Double)q.list().get(0);
			if(returnVal==null){
				returnVal=0.0;
			}
		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}
		return returnVal;
	}
	
	
	/**
	 * Retrieve a transaction using the registrant ID. There should only be one
	 * transaction per registrant.
	 * 
	 * @ejb.interface-method view-type="both"
	 * 
	 */
	public Double getTotalRegisteredTxValue(){
		Session hSession = null;
		Double returnVal=0.0;
		try {
			hSession = EJCUtils.getHibernateSession();
			ConventionExecutive exec=(ConventionExecutive)hSession.load(ConventionExecutive.class,new Integer(BATCH_EXEC));
			Query q=hSession.createQuery("select sum(transaction.transactionAmount) from Transaction transaction where transaction.conventionExecutive <>?");
			q.setParameter(0,exec);
			returnVal=(Double)q.list().get(0);
			if(returnVal==null){
				returnVal=0.0;
			}
		} catch (Exception e) {
			log.fatal(e);
		} finally {
			hSession.close();
		}
		return returnVal;
	}
	
	
	
	
	
	
	
	

}
